package org.hry.socket.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @Desc
 * @Author houry
 * @Date 2021/2/19 9:34
 **/
public class SocketServer {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel socketChannel = ServerSocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.socket().bind(new InetSocketAddress(9999));
        Selector selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            // 该方法会阻塞等待，直到有一个或者多个通道准备好了IO操作，或者超时
            selector.select();
            // 已经选择的键集
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            // 处理选择键集事件
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 处理掉后将键移除，避免重复消费(因为下次选择后，还在已选择键集中)
                iterator.remove();
                if (key.isAcceptable()) {
                    SocketChannel accept = ((ServerSocketChannel) key.channel()).accept();
                    accept.configureBlocking(false);
                    accept.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                    // keys为所有键，除掉serverSocket注册的键就是已连接socketChannel的数量
//                    String message = "连接成功 你是第" + (selector.keys().size() - 1) + "个用户";
                    String message = "00018";
                    //向客户端发送消息
                    accept.write(ByteBuffer.wrap(message.getBytes()));
                    InetSocketAddress address = (InetSocketAddress) accept.getRemoteAddress();
                    //输出客户端地址
                    System.out.println(address.getHostString() + ":" + address.getPort() + "\t");
                    System.out.println("客戶端已连接");
                    System.out.println("=========================================================");
                }
                if (key.isReadable()) {
                    SocketChannel socket = (SocketChannel) key.channel();
                    InetSocketAddress address = (InetSocketAddress) socket.getRemoteAddress();
                    System.out.println(address.getHostString() + ":" + address.getPort() + "\t");
                    ByteBuffer bf = ByteBuffer.allocate(1024 * 4);
                    int len = 0;
                    byte[] res = new byte[1024 * 4];
                    //捕获异常，因为在客户端关闭后会发送FIN报文，会触发read事件，但连接已关闭,此时read()会产生异常
                    try {
                        while ((len = socket.read(bf)) != 0) {
                            bf.flip();
                            bf.get(res, 0, len);
                            System.out.println(new String(res, 0, len));
                            bf.clear();
                        }
                        System.out.println("=========================================================");
                    } catch (IOException e) {
                        //客户端关闭了
                        key.cancel();
                        socket.close();
                        System.out.println("客戶端已断开");
                        System.out.println("=========================================================");
                    }
                }
                if (key.isWritable()){

                }
            }

        }

    }
}
